﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Diagnostics;
using DARE.Effects.RenderEffect;

namespace DARE
{
    public class CMeshPart // : IOrderedDraw
    {
        #region Fields

        private GraphicsDevice m_graphicDevice;
        private ModelMeshPart m_meshPart;
        private bool m_visible = true;
        private CMesh m_mesh;
        private bool m_transparency = false;
        private int m_partId;
        private CEffect m_effect = null;
        private CEffectTextures m_effectsParam;

        #endregion

        #region CTOR

        public CMeshPart(ModelMeshPart _part, CMesh _parent, int _partid)
        {
            DepthStencilState = null;

            this.Effect = _parent.Model.Effect;

            this.m_meshPart = _part;
            this.m_graphicDevice = _part.VertexBuffer.GraphicsDevice;
            this.m_mesh = _parent;
            this.m_partId = _partid;

            //if (this.m_mesh.Model.CanBeAnimated)
            //    this.m_effectId = CEffectBank.GetShaderId("", EEffectOption.ANIMATION);

            //Drawable = true;
        }

        #endregion

        #region Property

        // public bool IsInTheOrderer { get; set; }

        public DepthStencilState DepthStencilState { get; set; }

        //public bool Drawable { get; set; }

        public CEffect Effect
        {
            get { return this.m_effect; }
            set
            {
                if (this.m_effect != value)
                    this.m_effect = value;
            }
        }

        public ModelMeshPart MeshPart
        {
            get { return this.m_meshPart; }
        }

        public string Name
        {
            get { return this.m_mesh.Name + "-" + this.m_partId; }
        }

        //public uint EffectId
        //{
        //    get
        //    {
        //        if (this.m_effect == null)
        //        {
        //            if (this.m_mesh.Effect != null)
        //                return this.m_mesh.Effect.BasicEffect.Id;
        //            return this.m_mesh.Model.Effect.BasicEffect.Id;
        //        }
        //        return this.m_effect.BasicEffect.Id;
        //    }
        //}

        //public string UniqueId
        //{
        //    get { throw new NotImplementedException(); }
        //}

        public float CameraDistance
        {
            get
            {
                CModel _model = this.m_mesh.Model;
                if (_model.Node.Render3D.CameraMgr.ActiveCamera == null)
                    return 0.0f;
                return Vector3.Distance(_model.ModelWorld.Translation,
                                        _model.Node.Render3D.CameraMgr.ActiveCamera.Position); ;
            }
        }

        //public bool IsTransparency
        //{
        //    get { return this.m_mesh.Model.IsTransparence || this.m_transparency; }
        //    set
        //    {
        //        if (this.m_transparency != value)
        //        {
        //            Debug.Assert(this.TransparencyChanged != null);
        //            this.m_transparency = value;
        //            this.TransparencyChanged.Invoke(this, !value);
        //        }
        //    }
        //}

        //public CRasterizationContent State
        //{
        //    get { return this.m_mesh.State; }
        //}

        //public bool NodeInformationChanged { get; set; }

        public bool Visible
        {
            get { return this.m_visible & this.m_mesh.Drawable & this.m_mesh.Model.Drawable; }
            set
            {
                if (this.m_visible != value)
                    this.m_visible = value;
            }
        }

        public bool CanSort
        {
            get { return false; }
        }

        #endregion

        #region Method

        public void InitializeEffect()
        {
            //this.Effect = new CEffect((this.m_mesh.Effect == null) ? this.m_mesh.Model.Effect : this.m_mesh.Effect);
            if (this.m_meshPart.Tag is CEffectTextures)
            {
                m_effectsParam = this.m_meshPart.Tag as CEffectTextures;
                this.Effect.ColorMap = m_effectsParam.Texture;
                this.Effect.Brighteness = m_effectsParam.SpecularPower;
                this.Effect.Alpha = m_effectsParam.Alpha;
            }
        }

        public void Draw(GameTime gameTime)
        {
            Debug.Assert(Visible);
            //Debug.Assert(this.Drawable);

            this.m_graphicDevice.SetVertexBuffer(this.m_meshPart.VertexBuffer);
            if ((object)this.m_graphicDevice.Indices != (object)this.m_meshPart.IndexBuffer)
                this.m_graphicDevice.Indices = this.m_meshPart.IndexBuffer;

           // CEffect cbe = (this.m_effect == null) ? ((this.m_mesh.Effect == null) ? this.m_mesh.Model.Effect : this.m_mesh.Effect) : this.m_effect;
            CEffect cbe = this.Effect;


            //EffectTechnique old = cbe.CurrentTechnique;

            if (this.m_mesh.Model.AnimationController != null && this.m_mesh.IsSkinned) //&& this.m_mesh.Model.AnimationController is CBonesController
            {
                CAnimationController bc = this.m_mesh.Model.AnimationController;

                cbe.Bones = bc.SkinningTransform;

            }

            //m_mesh.Model.Node.Render3D.EffectMgr.s SetEffectGlobalValues(ref cbe);
            //if (m_effectsParam != null)
            //{
            //    if (m_effectsParam.Texture != null)
            //        cbe.ColorMap = m_effectsParam.Texture;
            //    //if (m_effectsParam.Specular != null)
            //    //{
            //    //    cbe.SpecularMapEnabled = true;
            //    //    cbe.SpecularMap = m_effectsParam.Specular;
            //    //}
            //    //else
            //    //{
            //    //    cbe.spec = false;
            //    //    cbe.SpecularIntensity = m_effectsParam.SpecularPower;
            //    //}
            //    //cbe.SpecularColor = new Color(m_effectsParam.SpecularColor);
            //    //cbe.DiffuseColor = new Color(m_effectsParam.DiffuseColor);
            //    cbe.Brighteness = m_effectsParam.SpecularPower;
            //    cbe.Alpha = m_effectsParam.Alpha;
            //}
            //else if (m_effect != null)
            //    cbe.ColorMap = m_effect.ColorMap;



            
            
            cbe.World = this.m_mesh.MeshWorld;
            //cbe.WorldInverse = Matrix.Transpose(Matrix.Invert(cbe.World));
            // CCamera cam = m_mesh.Model.Renderer.CameraMgr.GetCamera("ShadowsCamera");

            // global effects parameters.

            //m_mesh.Model.Effect.DiffuseColor = Color.White;

            //   cbe.SpecularIntensity = 0.15f;


            cbe.ProcessEffect(m_mesh.Model.Node.Render3D);

            


            EffectPassCollection _passes = cbe.Effect.CurrentTechnique.Passes;
            for (int i = 0; i < _passes.Count; ++i)
            {
                DepthStencilState dss = DepthStencilState.Default;
                if (DepthStencilState != null)
                {
                    dss = m_graphicDevice.DepthStencilState;
                    m_graphicDevice.DepthStencilState = DepthStencilState;
                }
                _passes[i].Apply();
                this.m_graphicDevice.DrawIndexedPrimitives(this.m_mesh.PrimitiveType, this.m_meshPart.VertexOffset, 0,
                    this.m_meshPart.NumVertices, this.m_meshPart.StartIndex, this.m_meshPart.PrimitiveCount);
                if (DepthStencilState != null)
                {
                    m_graphicDevice.DepthStencilState = dss;
                }
            }

            //cbe.CurrentTechnique = old;

        }

        //internal void TransparencyModelChanged(bool _old)
        //{
        //    if (this.TransparencyChanged != null)
        //        this.TransparencyChanged.Invoke(this, _old);
        //}

        //internal void DataChanged()
        //{
        //    this.NodeInformationChanged = true;
        //}


        public void InitializeDraw(GameTime _time) { }

        //public int Compare(IOrderedDraw a, IOrderedDraw b)
        //{
        //    throw new NotImplementedException();
        //}

        public override string ToString()
        {
            return this.Name;
        }

        #endregion

        #region Event

        public event DataChanged<IOrderedDraw, bool> TransparencyChanged;

        #endregion
    }
}
